// Contient toutes les spécifications de classes nécessaires
// pour représenter l'arbre abstrait
#ifndef ARBRE_H_
#define ARBRE_H_

#include <vector>
#include <iostream>
#include <iomanip>
using namespace std;

#include "Symbole.h"
#include "Valeur.h"

////////////////////////////////////////////////////////////////////////////////
template <class T>
class Noeud {
// classe abstraite dont dériveront toutes les classes servant à représenter l'arbre abstrait
// Remarque : la classe ne contient aucun constructeur
  public:
    virtual Valeur<T> getValeur(); // méthode pure (non implémentée) qui rend la classe abstraite // =Valeur(0)
    virtual void afficher(unsigned short indentation=0) { cout << setw(4*indentation) << " "; }
      // pour afficher un noeud avec un décalage (indentation) proportionnel à son niveau dans l'arbre

    virtual ~Noeud() {} // présence d'un destructeur virtuel conseillée dans les classes abstraites
};

////////////////////////////////////////////////////////////////////////////////
template <class T>
class NoeudSeqInst : public Noeud<T> {
// classe pour représenter un noeud "sequence d'instruction"
// qui a autant de fils que d'instructions dans la séquence
  public:
     NoeudSeqInst();   // construit une séquence d'instruction vide
    ~NoeudSeqInst() {} // à cause du destructeur virtuel de la classe Noeud
    Valeur<T> getValeur(); // évalue chaque instruction de la séquence
    void afficher(unsigned short indentation=0); // affiche la séquence d'instructions
    void ajouteInstruction(Noeud<T>* instruction);  // ajoute une instruction à la séquence

  private:
    vector<Noeud<T> *> tabInst; // pour stocker les instructions de la séquence
};


////////////////////////////////////////////////////////////////////////////////
template <class T>
class NoeudPour : public Noeud<T> {
// classe pour représenter un noeud "repeter"
// composé de 2 fils : la seqInst et la condition de sortie
  public:
	NoeudPour(Noeud<T>* aff, Noeud<T>* affDroite, Noeud<T>* expbool, Noeud<T>* seqInst); // construit une affectation
    ~NoeudPour() {} // à cause du destructeur virtuel de la classe Noeud
    Valeur<T> getValeur(); // évalue l'expression et affecte sa valeur à la variable
    void afficher(unsigned short indentation=0); // affiche l'affectation

  private:
    Noeud<T>* seqInst;
    Noeud<T>* expBool;
    Noeud<T>* aff;
    Noeud<T>* affDroite;
};


////////////////////////////////////////////////////////////////////////////////
template <class T>
class NoeudSi : public Noeud<T> {
// classe pour représenter un noeud "si"
// composé de 3 fils : la seqInst et la condition d'entre, et le si suivant s'il existe.
  public:
	NoeudSi(Noeud<T>* expbool, Noeud<T>* seqInst, Noeud<T>* siSuivant); // construit une affectation
    ~NoeudSi() {} // à cause du destructeur virtuel de la classe Noeud
    Valeur<T> getValeur(); // évalue l'expression et affecte sa valeur à la variable
    void afficher(unsigned short indentation=0); // affiche l'affectation

  private:
    Noeud<T>* seqInst;
    Noeud<T>* expBool;
    Noeud<T>* siSuivant;
};



////////////////////////////////////////////////////////////////////////////////
template <class T>
class NoeudTantQue : public Noeud<T> {
// classe pour représenter un noeud "repeter"
// composé de 2 fils : la seqInst et la condition de sortie
  public:
	NoeudTantQue(Noeud<T>* expbool, Noeud<T>* seqInst); // construit une affectation
    ~NoeudTantQue() {} // à cause du destructeur virtuel de la classe Noeud
    Valeur<T> getValeur(); // évalue l'expression et affecte sa valeur à la variable
    void afficher(unsigned short indentation=0); // affiche l'affectation

  private:
    Noeud<T>* seqInst;
    Noeud<T>* expBool;
};

////////////////////////////////////////////////////////////////////////////////
template <class T>
class NoeudRepeter : public Noeud<T> {
// classe pour représenter un noeud "repeter"
// composé de 2 fils : la seqInst et la condition de sortie
  public:
	NoeudRepeter(Noeud<T>* expbool, Noeud<T>* seqInst); // construit une affectation
    ~NoeudRepeter() {} // à cause du destructeur virtuel de la classe Noeud
    Valeur<T> getValeur(); // évalue l'expression et affecte sa valeur à la variable
    void afficher(unsigned short indentation=0); // affiche l'affectation

  private:
    Noeud<T>* seqInst;
    Noeud<T>* expBool;
};

////////////////////////////////////////////////////////////////////////////////
template <class T>
class NoeudAffectation : public Noeud<T> {
// classe pour représenter un noeud "affectation"
// composé de 2 fils : la variable et l'expression qu'on lui affecte
  public:
     NoeudAffectation(Noeud<T>* variable, Noeud<T>* expression); // construit une affectation
    ~NoeudAffectation() {} // à cause du destructeur virtuel de la classe Noeud
    Valeur<T> getValeur(); // évalue l'expression et affecte sa valeur à la variable
    void afficher(unsigned short indentation=0); // affiche l'affectation

  private:
    Noeud<T>* variable;
    Noeud<T>* expression;
};

////////////////////////////////////////////////////////////////////////////////
template <class T>
class NoeudDeclaration : public Noeud<T> {
// classe pour représenter un noeud "affectation"
// composé de 2 fils : la variable et l'expression qu'on lui affecte
  public:
     NoeudDeclaration(Noeud<T>* variable, Symbole type); // construit une affectation
    ~NoeudDeclaration() {} // à cause du destructeur virtuel de la classe Noeud
    Valeur<T> getValeur(); // évalue l'expression et affecte sa valeur à la variable
    void afficher(unsigned short indentation=0); // affiche l'affectation

  private:
    Noeud<T>* variable;
    Symbole type;
};

////////////////////////////////////////////////////////////////////////////////
template <class T>
class NoeudEcrire : public Noeud<T> {
// classe pour représenter un noeud "ecrire"
// composé de 1 fils : l'expression qu'on veux afficher
  public:
     NoeudEcrire(Noeud<T>* expression); // construit une expression
    ~NoeudEcrire() {} // à cause du destructeur virtuel de la classe Noeud
    Valeur<T> getValeur(); // revoie la valeur de l'expression
    void afficher(unsigned short indentation=0); // affiche le ecrire

  private:
    Noeud<T>* expression;
};

////////////////////////////////////////////////////////////////////////////////
template <class T>
class NoeudLire : public Noeud<T> {
// classe pour représenter un noeud "lire"
// composé de 1 fils : la varialbe que l'on veut affecter
  public:
	NoeudLire(Noeud<T>* variable); // construit une expression
    ~NoeudLire() {} // à cause du destructeur virtuel de la classe Noeud
    Valeur<T> getValeur(); // revoie la valeur de l'expression
    void afficher(unsigned short indentation=0); // affiche le lire

  private:
    Noeud<T>* variable;
};


////////////////////////////////////////////////////////////////////////////////
template <class T>
class NoeudOperateurBinaire : public Noeud<T> {
// classe pour représenter un noeud "opération arithmétique" composé d'un opérateur (+-*/)
// et de 2 fils : l'opérande gauche et l'opérande droit
  public:
    NoeudOperateurBinaire(Symbole operateur, Noeud<T>* operandeGauche, Noeud<T>* operandeDroit);
     // construit une opération binaire : operandeGauche operateur OperandeDroit
   ~NoeudOperateurBinaire() {} // à cause du destructeur virtuel de la classe Noeud
   Valeur<T> getValeur(); // évalue l'operande gauche, l'operande droit et applique l'opérateur
    void afficher(unsigned short indentation=0); // affiche l'opération

  private:
    Symbole operateur;
    Noeud<T>*  operandeGauche;
    Noeud<T>*  operandeDroit;
};

#endif /* ARBRE_H_ */
